﻿#pragma once

#include "../command/command.hh"
#include "../http/http_call.hh"
#include "../util/box_std_allocator.hh"
#include <unordered_map>

namespace kratos {
namespace service {

class CommandManager;

/**
 * 命令处理器.
 */
class CommandImpl : public Command {
  struct CommandProcCount {
    CommandProc proc;                 ///< 命令处理函数
    std::size_t count{0};             ///< 当前是否有调用，未完成的调用次数
    std::time_t max_exec_time{10000}; ///< 最大执行时间
  };
  using ProcMap = std::unordered_map<
      std::string,
      CommandProcCount,
      std::hash<std::string>,
      std::equal_to<std::string>,
      Allocator<std::pair<const std::string, CommandProcCount>>
  >;
  ProcMap proc_map_; ///< 调用表
  struct ProcInfo {
    std::string reason;        ///< 命令名
    std::time_t deadline{0};   ///< 超时时间戳，毫秒s
    http::HttpCallPtr callPtr; ///< 本次的HTTP调用
    std::uint64_t coid{0};     ///< 本次调用的协程ID
  };
  using ProcessMap = std::unordered_map<
      std::uint64_t,
      ProcInfo,
      std::hash<std::uint64_t>,
      std::equal_to<std::uint64_t>,
      Allocator<std::pair<const std::uint64_t, ProcInfo>>
  >;
  ProcessMap process_map_;           ///< 未完成的调用表
  std::uint64_t proc_id_{1};         ///< 调用ID
  CommandManager *manager_{nullptr}; ///< 命令管理器

public:
  /**
   * 构造.
   *
   * \param manager 命令管理器
   */
  CommandImpl(CommandManager *manager);
  /**
   * 析构.
   *
   */
  virtual ~CommandImpl();
  /**
   * 注册命令处理器.
   *
   * \param name 命令名
   * \param max_exec_time 最大执行超时时间，毫秒
   * \param proc 处理器
   * \return true或false
   */
  virtual auto wait_for(const std::string &name, std::time_t max_exec_time,
                        CommandProc proc) -> bool override;

  virtual auto wait_path(const std::string& path, std::time_t max_exec_time,
      CommandProc proc) -> bool override;
  /**
   * 逻辑主循环.
   *
   * \param ms 当前时间戳，毫秒
   * \return
   */
  virtual auto update(std::time_t ms) -> void;

public:
  /**
   * 处理命令.
   *
   * \param callPtr HTTP请求
   * \param name 命令名
   * \param content 命令内容
   * \return true或false
   */
  auto on_command(http::HttpCallPtr callPtr, const std::string &name,
                  const std::string &content) -> bool;
  /**
   * 与管理器脱离
   */
  auto detach()->void;
};

} // namespace service
} // namespace kratos
